<?php
namespace PsiFramework\Classes\Util\HTTP;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */


/**
 * The HTTPRequest class allows to launch HTTP requests
 * inside a page and be used as a proxy or to include
 * dynamic generated pages inside your own page.
 *
 * @package classes.util
 */
class HTTPRequest
{

    /**
     * @var string    the "GET" request type
     */
    public static /*string*/ $get = "GET" ;
    /**
     * @var string    the "POST" request type
     */
    public static /*string*/ $post = "POST" ;

    protected /*URI*/      $_uri ;
    protected /*array*/    $_parameters ;
    protected /*int*/      $_timeout ;

    /**
     * HTTPRequest constructor
     *
     * @param $uriString  the uri that must be called
     * @param $parameters the array of parameters formatted
     *                    as $tab["parameterName"] = $parameter
     * @param $timeout    the timeout of the request
     */
    public function __construct(
        /*string*/ $uriString,
        /*array*/ $parameters=array(),
        /*int*/ $timeout=30
    )
    {

        $this->_uri = parse_url($uriString);
        if (!isset($this->_uri['port'])) {
            $this->_uri['port'] = 80 ;
        }
        $this->_parameters = $parameters ;
        $this->_timeout = $timeout ;

    }

    /**
     * This function allows to add a parameter to the request
     *
     * @param $paramName    the name of the parameter
     * @param $paramValue    the value of the parameter
     */
    public function addParameter(/*string*/ $paramName, /*string*/ $paramValue)
    {
        $this->_parameters[$paramName] = $paramValue ;
    }

    /**
     * This function executes the built HTTP request
     *
     * @param $requestType    the request type (POST or GET)
     * @return string
     */
    public function execute(/*string*/ $requestType)
    {

        $return = "" ;

        if ($requestType == self::$get || $requestType == self::$post) {

            $args = http_build_query($this->_parameters);

            $fp = fsockopen(
                $this->_uri['host'], 
                $this->_uri['port'], 
                $errno, 
                $errstr, 
                $this->_timeout
            );
            if (!$fp) {

                throw new \Exception("$errstr ($errno)");

            } else {

                $path = '/' ;
                if (isset($this->_uri['path'])) {
                    $path = $this->_uri['path'] ;
                }

                $query = '' ;
                if (isset($this->_uri['query'])
                    &&!isNullOrEmptyString($this->_uri['query'])
                ) {
                    $query = '?' . $this->_uri['query'] ;
                }

                $request  = $requestType . " " . $path.$query . " HTTP/1.1\n";
                $request .= "Host: " . $this->_uri['host'] . "\n";
                $request .= "Connection: Close\r\n" ;
                $request .= "Content-type: application/x-www-form-urlencoded\n";
                $request .= "Content-length: " . strlen($args) . "\n\n";
                $request .= $args . "\n";

                fwrite($fp, $request);

                $response = "" ;
                while (!feof($fp)) {
                    $response .= fgets($fp, 512);
                }
                fclose($fp);

                $return = $this->processResponse($response);

            }

        } else {

            $return = "Invalid Request !" ;

        }

        return $return ;

    }

    /**
     * This function parses the response passed as an argument
     *
     * @param $response    the response to parse
     * @return string
     */
    protected function processResponse(/*string*/ $response)
    {

        $return = "" ;

        $chunks = explode("\r\n\r\n", trim($response));
        if ($this->checkHeaders($chunks[0])) {
            return $chunks[1] ;
        } else {
            throw new \Exception("Bad response !"); ;
        }



    }

    /**
     * This function checks if the response headers are
     * valid headers of a succeeded request
     *
     * @param $headers    the headers to check
     * @return boolean
     */
    protected function checkHeaders(/*string*/ $headers)
    {

        $startPos = strpos(mb_strtoupper($headers, 'utf-8'), "HTTP/1.") + 9 ;
        $code = substr($headers, $startPos, 3);

        return ($code == "100" || $code == "200");

    }

}

